#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include <vector>
#include <queue>
#include "Thread.hpp"
using namespace std;

struct ThreadData
{
    pthread_t tid;
    string name;
};

// T表示任务的类型
template<class T>
class ThreadPool
{
    static const size_t defaultNum = 5;
private:
    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void UnLock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void ThreadWake()
    {
        pthread_cond_signal(&_cond);
    }

    void ThreadSleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    bool IsQueueEmpty()
    {
        return _tasks.empty();
    }

    string GetName(pthread_t& t)
    {
        for(auto& e : _threads) {
            if(e.GetTid() == t) 
                return e.GetName();
        }
        return "";
    }
public:
    ThreadPool(size_t num = defaultNum)
    {
        for(size_t i = 0; i < num;++i) {    
            // Thread<void*> t(fun);
            _threads.push_back(Thread<void*>(StartRoutine, this));
        }
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    // 线程执行任务，不需要this指针，所以设置成static
    static void StartRoutine(void* args)
    {   
        ThreadPool* tp = static_cast<ThreadPool*>(args);
        pthread_t self = pthread_self();
        string name = tp->GetName(self);
        while(true) {
            tp->Lock();
            // while循环判断防止误唤醒
            while(tp->IsQueueEmpty()) {
                tp->ThreadSleep();
            }
            T t = tp->Pop();
            tp->UnLock();
            t.Run();
            printf("%s, res: %s\n", name.c_str(), t.GetResult().c_str());
        }
        // return nullptr;
    }

    // 创建进程
    void Start()
    {
        int num = _threads.size();
        // for (size_t i = 0; i < num; i++) {
        //     _threads[i].name = "Thread-" + to_string(i+1);
        //     pthread_create(&(_threads[i].tid), nullptr, StartRoutine, this);
        // }
        for (size_t i = 0; i < num; i++) {
            _threads[i].Run();
        }
    }

    T Pop()
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    // 添加任务
    void Push(const T& t)
    {
        Lock();
        _tasks.push(t);
        ThreadWake();
        UnLock();
    }
private:
    vector<Thread<void*>> _threads;
    queue<T> _tasks;    // 任务，这是临界资源
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};